#pragma once

#include <initializer_list>
#include <iterator>


namespace msl {
template<typename T>
class List {
    public:
    struct ListElement {
        T value;
        ListElement *previous;
        ListElement *next;
    };

    class ListIterator {
        public:
        using iterator_category = std::bidirectional_iterator_tag;
        using difference_type = std::ptrdiff_t;
        using value_type = T;
        using pointer = T*;
        using reference = T&;
     
        public:
        friend class List;

        private:
        ListElement *el;

        private:
        ListElement* getptrListElement() const;

        public:
        ListIterator();
        ListIterator(ListElement *ptr);

        reference operator*() const;
        pointer operator->();

        ListIterator& operator++();
        ListIterator operator++(int);
        ListIterator& operator--();
        ListIterator operator--(int);

        // friend bool operator== (const ListIterator& a, const ListIterator& b);
        // friend bool operator!= (const ListIterator& a, const ListIterator& b);
        bool operator== (const ListIterator& other);
        bool operator!= (const ListIterator& other); 
    };
    
    private:
    ListElement *head;
    ListElement *tail;

    private:
    void init_empty();

    public:
    List();
    List(const List &other);
    List(std::initializer_list<T> values);
    ~List();
    void copy(const List &other);
   
    List<T> operator=(const List &other);

    ListIterator begin();
    ListIterator end();

    bool empty() const;
    void clear();
    T get_front() const;
    T get_back() const;
    void push_front(T el);
    void push_back(T el);
    void pop_front();
    void pop_back();
    T pullout_front();    
    T pullout_back();
    void insert(ListIterator it, T value);
    void erase(ListIterator it);
    void erase(ListIterator lit, ListIterator rit);

};
}

#include "list.hpp"

